This is a demonstration of how the process might work by hand.
Measurement is obviously trickier but I used the ruler tool in GiMP to show the process.
## Loading required package: magrittr
##
## Attaching package: 'imager'
## The following object is masked from 'package:magrittr':
##
## add
## The following objects are masked from 'package:stats':
##
## convolve, spectrum
## The following object is masked from 'package:graphics':
##
## frame
## The following object is masked from 'package:base':
##
## save.image
## ── Attaching packages ─────────────────────────────────────── tidyverse 1.3.0 ──
## ✓ ggplot2 3.3.3 ✓ purrr 0.3.4
## ✓ tibble 3.0.5 ✓ dplyr 1.0.3
## ✓ tidyr 1.1.2 ✓ stringr 1.4.0
## ✓ readr 1.4.0 ✓ forcats 0.5.0
## ── Conflicts ────────────────────────────────────────── tidyverse_conflicts() ──
## x imager::add() masks magrittr::add()
## x stringr::boundary() masks imager::boundary()
## x tidyr::extract() masks magrittr::extract()
## x tidyr::fill() masks imager::fill()
## x dplyr::filter() masks stats::filter()
## x dplyr::lag() masks stats::lag()
## x purrr::set_names() masks magrittr::set_names()
# Remove EverOS ruler
crop_everos <- function(im) {
# Cut out yellow/red area
img_bbox <- im %>%
imsplit(axis = "c") %>%
(function(x) is.finite((x[[1]] + x[[2]])/x[[3]])) %>%
as.cimg() %>%
(function(x) x == 1)
crop.bbox(im, img_bbox) %>%
# convert to grayscale
grayscale() %>%
# Autocrop each half of the image
ImageAlignR::map_halfimg(fun = autocrop) %>%
# Crop 5px from each side to clean residual bits up
crop.borders(nx = 5, ny = 5) %>%
# Crop out extra white space
autocrop() %>%
# Convert to black and white
threshold() %>%
# Clean up fuzz (at most 3x3 px)
shrink(3) %>%
grow(3) %>%
# Crop again
autocrop()}
Cleaning the image requires that we have a minimum “interesting” size and shape - this is used to define a filter. Many of these filters work better on an inverted image.
Measuring the dots in the ECCO shoes in an image editing program, we can see that the small dots are ~ 25 px across. Our filter, thus, is a circular matrix with radius 10 pixels - smaller than the small dots we want to keep.
### Check basic shape statistics
This portion of the algorithm explicitly depends on the size and shape of the dominant feature in the shoe. It would have to be modified to work with e.g. hexagons or rectangles, and would still only work for a regular pattern of the same shape.
As part of the shape filtering, we calculate the center (median) of each shape. This obviously doesn’t work properly for concave shapes, but for circles it is just fine.
##
## Attaching package: 'tripack'
## The following object is masked from 'package:imager':
##
## circles